﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Data.Linq;
using System.Web.Mvc;
using System.Linq.Expressions;
using Vit.Common.Providers;
using Vit.Common.Extensions;
using Vit.Common.Helpers;
using Vit.Web.Providers;

namespace Vit.Web.Providers.DataSource
{
    public class DataContextEntitySourceProvider : Vit.Web.Providers.IDataSourceProvider
    {
        protected ICacheProvider cache;

        public DataContextEntitySourceProvider(Type dataContextType, Type entityType, string textField, string valueField, ICacheProvider cache)
        {
            DataContextType = dataContextType;
            EntityType = entityType;
            TextFieldName = textField;
            ValueFieldName = valueField;
            this.cache = cache;
        }

        public virtual string BuildCacheKey()
        {
            return string.Format("CachedDataSource:{0}", EntityType.FullName);
        }

        protected virtual object Create(string categoryName, string text)
        {
            object entity = Activator.CreateInstance(EntityType);
            entity.SetPropertyValue(TextFieldName, text);
            return entity;
        }

        #region IDataSourceService Members

        public virtual IEnumerable<SelectListItem> GetSourceList(string categoryName)
        {
            string key = BuildCacheKey();
            if (cache != null && cache.Contains(key))
                return cache.GetData(key) as IEnumerable<SelectListItem>;

            DataContext db = Activator.CreateInstance(DataContextType) as DataContext;
            db.ObjectTrackingEnabled = false;
            var query = db.GetTable(EntityType).AsQueryable();
            List<SelectListItem> items = new List<SelectListItem>();
            foreach(var o in query)
            {
                SelectListItem item = new SelectListItem();
                item.Text = (o.GetPropertyValue(TextFieldName) ?? "").ToString();
                item.Value = (o.GetPropertyValue(ValueFieldName) ?? "").ToString();

                items.Add(item);
            }

            if (cache != null)
                cache.Add(key, items, new string[] { EntityType.FullName }, TimeSpan.FromHours(24), DateTime.MaxValue);

            return items;
        }

        public virtual string GetTextByValue(string categoryName, object id)
        {
            var items = GetSourceList(categoryName);
            var item = items.FirstOrDefault(o => o.Value == id.ToString());
            return item == null ? string.Empty : item.Text;
        }

        public virtual string GetValueByText(string categoryName, string text, bool insertIfNotExists)
        {
            var items = GetSourceList(categoryName);
            var item = items.FirstOrDefault(o => o.Text == text);
            if (item != null)
                return item.Value;
            if (insertIfNotExists)
            {
                var obj = Create(categoryName, text);
                if (obj != null)
                {
                    DataContext db = Activator.CreateInstance(DataContextType) as DataContext;
                    var tbl = db.GetTable(EntityType);
                    tbl.InsertOnSubmit(obj);
                    db.SubmitChanges();

                    if (cache != null)
                    {
                        string key = BuildCacheKey();
                        cache.Remove(key);
                        cache.RemoveDependencySet(new string[] { EntityType.FullName });
                    }
                    return GetValueByText(categoryName, text, false);
                }
            }
            return string.Empty;
        }

        #endregion

        public Type DataContextType { get; set; }
        public Type EntityType { get; set; }
        public string TextFieldName { get; set; }
        public string ValueFieldName { get; set; }

        #region IProvider Members

        public string Name
        {
            get { return string.Format("DataSource:{0}", EntityType.FullName); }
        }

        #endregion
    }
}
